"""

File: ioml.py
Author: Michael Hoover

IOML stands for Interactive Outline Markup Language. It is a wrapper around an IOelement that provides additional information for processing IOelements
in CoffeeTalk.

Requires the ElementTree library for building an ioml object from an XML string.

"""

import urllib
from xml.etree import cElementTree as etree
import ioelement

VERSION            = "1.0"

TERMINATOR         = "</ioml>"


class IOML(object):
        
    def __init__(self,headelement=None,bodyelement=None,iomlstring='',filepath='',url='',iomltree=None,nodetype=ioelement.IOElement,encoded=True):
        """ Initialize a new ioml object. 
        
        Keyword arguments:
        headelement -- The IOelement to use in the 'head' portion of the ioml object (default None)
        bodyelement -- The IOelement to use in the 'body' portion of the ioml object (default None)
        iomlstring -- A valid string representation of a ioml object (default '')
        filepath -- Location of a local file to load into a ioml object (default '')
        url -- URI pointing to a valid string representation of a ioml object (default '')
        iomltree -- An ElementTree representing a valid ioml object in XML
        """
            
        self.headelement = headelement
        self.bodyelement = bodyelement
        
        self.nodetype = nodetype
        self.encoded = encoded
        
        if iomlstring != '':
            self.__make_ioml_from_string(iomlstring)
        elif filepath != '':
            self.__make_ioml_from_file(filepath)
        elif url != '':
            self.__make_ioml_from_url(url)
        elif iomltree != None:
            self.__make_ioml_from_ElementTree(iomltree)
    
    def __repr__(self):
        """Returns a string representation of this ioml object. """
        return self.to_string()
    
    def __str__(self):
        """ Returns a string representation of this ioml object. """ 
        return self.to_string()
    
    def to_string(self):
        """Returns a string representation of this ioml object. """ 
        
        returnstring = ''.join(('<ioml v="' ,VERSION ,'">'))
        
        if self.headelement != None:
            returnstring = ''.join((returnstring,'<h>',str(self.headelement),'</h>'))
        else:
            returnstring = ''.join((returnstring,'<h />'))
        if self.bodyelement == None:
            returnstring = ''.join((returnstring,'<b />'))
        else:
            returnstring = ''.join((returnstring,'<b>',str(self.bodyelement),'</b>'))
        
        returnstring = ''.join((returnstring,'</ioml>'))
        
        return returnstring
    
    def __make_ioml_from_string(self,iomlstring):
        """Construct an ioml object from a string. """
        
        iomltree = etree.fromstring(iomlstring)
        self.__make_ioml_from_ElementTree(iomltree)
   
    def __make_ioml_from_file(self,filepath):
        """Construct a ioml object from a local file. """
        
        iomlstring = ''
        fobject = open(filepath)
        try:    
            iomlstring = fobject.read()
            fobject.close()
        except:
            fobject.close()
            raise
        finally:
            fobject.close()
        
        if iomlstring != '':
            self.__make_ioml_from_string(iomlstring)
    
    def __make_ioml_from_url(self,url):
        """Construct a ioml object from a remote file. """
        
        f = urllib.urlopen(url)
        iomlstring = f.read()
        f.close()
        
        if iomlstring != '':
            self.__make_ioelement_from_string(iomlstring)
    
    def __make_ioml_from_ElementTree(self,iomltree):
        """ Construct a ioml object from an ElementTree object. """
        
        root = iomltree.find("h")
        root = root.find("i")
        if root != None:
            self.headelement = self.nodetype(root.get("n"),attribs=root.attrib, encoded=self.encoded)
            root = root.find("i")
            if root != None:
                self.headelement.add(self.nodetype(root.get("n"),attribs=root.attrib, encoded=self.encoded))
            
        root = iomltree.find("b")
        root = root.find("i")
        try:
            self.bodyelement = self.nodetype(root.get("n"),attribs=root.attrib, encoded=self.encoded)
            self.__traverse_tree(root, self.bodyelement)                
        except:
            self.bodyelement = None
    
    def __traverse_tree(self,childelement,parentelement):
        """ Iterate through each child element and add them to the parentelement. """
        for elem in childelement.getchildren():
            elemtext = elem.get("n")
            parentelement[elemtext] = self.nodetype(elemtext,elem.attrib,encoded=self.encoded)
            if len(elem.getchildren()) > 0:
                self.__traverse_tree(elem,parentelement.childelements[elemtext])


